"""
持仓管理

提供持仓跟踪、风险控制、止损止盈等功能。
"""

from typing import Dict, List, Optional, Any, Callable
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from enum import Enum
import asyncio
from decimal import Decimal

from ..trading.order_manager import Order, OrderStatus, OrderType, OrderSide


class PositionType(Enum):
    """持仓类型"""
    LONG = "long"  # 多头
    SHORT = "short"  # 空头
    NEUTRAL = "neutral"  # 中性


class PositionStatus(Enum):
    """持仓状态"""
    OPEN = "open"  # 开仓
    PARTIAL = "partial"  # 部分平仓
    CLOSED = "closed"  # 已平仓
    SUSPENDED = "suspended"  # 暂停


class RiskLevel(Enum):
    """风险等级"""
    LOW = "low"  # 低风险
    MEDIUM = "medium"  # 中等风险
    HIGH = "high"  # 高风险
    CRITICAL = "critical"  # 严重风险


@dataclass
class PositionRisk:
    """持仓风险指标"""
    var_1d: Decimal = Decimal('0')  # 1日VaR
    var_5d: Decimal = Decimal('0')  # 5日VaR
    max_drawdown: Decimal = Decimal('0')  # 最大回撤
    volatility: float = 0.0  # 波动率
    beta: float = 0.0  # Beta系数
    correlation: float = 0.0  # 相关性
    concentration_risk: float = 0.0  # 集中度风险
    liquidity_risk: float = 0.0  # 流动性风险
    risk_level: RiskLevel = RiskLevel.LOW
    last_updated: datetime = field(default_factory=datetime.now)


@dataclass
class StopLoss:
    """止损设置"""
    enabled: bool = False
    stop_price: Optional[Decimal] = None
    stop_percentage: Optional[float] = None  # 止损百分比
    trailing_stop: bool = False  # 移动止损
    trailing_percentage: Optional[float] = None  # 移动止损百分比
    max_loss: Optional[Decimal] = None  # 最大亏损金额


@dataclass
class TakeProfit:
    """止盈设置"""
    enabled: bool = False
    target_price: Optional[Decimal] = None
    target_percentage: Optional[float] = None  # 止盈百分比
    partial_profit: bool = False  # 部分止盈
    profit_levels: List[tuple] = field(default_factory=list)  # [(价格/百分比, 数量比例)]


@dataclass
class PositionAlert:
    """持仓告警"""
    alert_id: str
    position_id: str
    alert_type: str  # price, pnl, risk, time
    condition: str  # >, <, >=, <=, ==
    threshold: Decimal
    message: str
    enabled: bool = True
    triggered: bool = False
    trigger_time: Optional[datetime] = None
    created_time: datetime = field(default_factory=datetime.now)


class Position:
    """
    持仓对象
    
    跟踪单个证券的持仓信息，包括数量、成本、盈亏等。
    """
    
    def __init__(
        self,
        position_id: str,
        symbol: str,
        position_type: PositionType = PositionType.LONG,
        initial_quantity: Decimal = Decimal('0'),
        initial_price: Decimal = Decimal('0')
    ):
        """初始化持仓"""
        self.position_id = position_id
        self.symbol = symbol
        self.position_type = position_type
        self.status = PositionStatus.OPEN
        self.created_time = datetime.now()
        
        # 持仓数量和价格
        self.quantity = initial_quantity
        self.average_price = initial_price
        self.current_price = initial_price
        self.cost_basis = initial_quantity * initial_price
        
        # 盈亏计算
        self.market_value = Decimal('0')
        self.unrealized_pnl = Decimal('0')
        self.realized_pnl = Decimal('0')
        self.total_pnl = Decimal('0')
        
        # 历史数据
        self.max_price = initial_price
        self.min_price = initial_price
        self.max_profit = Decimal('0')
        self.max_loss = Decimal('0')
        
        # 风险管理
        self.risk_metrics = PositionRisk()
        self.stop_loss = StopLoss()
        self.take_profit = TakeProfit()
        self.alerts: List[PositionAlert] = []
        
        # 交易记录
        self.trades: List[Dict[str, Any]] = []
        
        # 回调函数
        self.on_update_callbacks: List[Callable] = []
        self.on_alert_callbacks: List[Callable] = []
        
        # 初始更新
        self.update_market_value()
    
    def add_quantity(self, quantity: Decimal, price: Decimal) -> None:
        """增加持仓"""
        if self.position_type == PositionType.LONG:
            # 多头加仓
            total_cost = self.cost_basis + (quantity * price)
            total_quantity = self.quantity + quantity
            
            if total_quantity > 0:
                self.average_price = total_cost / total_quantity
                self.quantity = total_quantity
                self.cost_basis = total_cost
        else:
            # 空头加仓
            total_cost = self.cost_basis + (quantity * price)
            total_quantity = self.quantity + quantity
            
            if total_quantity > 0:
                self.average_price = total_cost / total_quantity
                self.quantity = total_quantity
                self.cost_basis = total_cost
        
        # 记录交易
        self.trades.append({
            'action': 'add',
            'quantity': quantity,
            'price': price,
            'timestamp': datetime.now()
        })
        
        self.update_market_value()
    
    def reduce_quantity(self, quantity: Decimal, price: Decimal) -> Decimal:
        """减少持仓"""
        if quantity > self.quantity:
            raise ValueError(f"减仓数量 {quantity} 超过持有数量 {self.quantity}")
        
        # 计算已实现盈亏
        if self.position_type == PositionType.LONG:
            realized_pnl = (price - self.average_price) * quantity
        else:
            realized_pnl = (self.average_price - price) * quantity
        
        self.realized_pnl += realized_pnl
        
        # 更新持仓
        self.quantity -= quantity
        self.cost_basis = self.quantity * self.average_price
        
        # 检查是否完全平仓
        if self.quantity == 0:
            self.status = PositionStatus.CLOSED
        elif self.quantity < self.cost_basis / self.average_price:
            self.status = PositionStatus.PARTIAL
        
        # 记录交易
        self.trades.append({
            'action': 'reduce',
            'quantity': quantity,
            'price': price,
            'realized_pnl': realized_pnl,
            'timestamp': datetime.now()
        })
        
        self.update_market_value()
        return realized_pnl
    
    def update_price(self, price: Decimal) -> None:
        """更新当前价格"""
        self.current_price = price
        
        # 更新历史极值
        if price > self.max_price:
            self.max_price = price
        if price < self.min_price:
            self.min_price = price
        
        self.update_market_value()
        self._check_alerts()
        self._check_stop_loss()
        self._check_take_profit()
    
    def update_market_value(self) -> None:
        """更新市值和盈亏"""
        if self.quantity == 0:
            self.market_value = Decimal('0')
            self.unrealized_pnl = Decimal('0')
        else:
            self.market_value = self.quantity * self.current_price
            
            if self.position_type == PositionType.LONG:
                self.unrealized_pnl = self.market_value - self.cost_basis
            else:
                self.unrealized_pnl = self.cost_basis - self.market_value
        
        self.total_pnl = self.unrealized_pnl + self.realized_pnl
        
        # 更新历史极值
        if self.unrealized_pnl > self.max_profit:
            self.max_profit = self.unrealized_pnl
        if self.unrealized_pnl < self.max_loss:
            self.max_loss = self.unrealized_pnl
        
        # 触发更新回调
        for callback in self.on_update_callbacks:
            try:
                callback(self)
            except Exception as e:
                print(f"持仓更新回调执行失败: {e}")
    
    def set_stop_loss(
        self,
        stop_price: Optional[Decimal] = None,
        stop_percentage: Optional[float] = None,
        trailing_stop: bool = False,
        trailing_percentage: Optional[float] = None
    ) -> None:
        """设置止损"""
        self.stop_loss.enabled = True
        self.stop_loss.stop_price = stop_price
        self.stop_loss.stop_percentage = stop_percentage
        self.stop_loss.trailing_stop = trailing_stop
        self.stop_loss.trailing_percentage = trailing_percentage
        
        # 如果设置了百分比止损，计算止损价格
        if stop_percentage and not stop_price:
            if self.position_type == PositionType.LONG:
                self.stop_loss.stop_price = self.average_price * Decimal(str(1 - stop_percentage / 100))
            else:
                self.stop_loss.stop_price = self.average_price * Decimal(str(1 + stop_percentage / 100))
    
    def set_take_profit(
        self,
        target_price: Optional[Decimal] = None,
        target_percentage: Optional[float] = None,
        partial_profit: bool = False,
        profit_levels: Optional[List[tuple]] = None
    ) -> None:
        """设置止盈"""
        self.take_profit.enabled = True
        self.take_profit.target_price = target_price
        self.take_profit.target_percentage = target_percentage
        self.take_profit.partial_profit = partial_profit
        
        if profit_levels:
            self.take_profit.profit_levels = profit_levels
        
        # 如果设置了百分比止盈，计算目标价格
        if target_percentage and not target_price:
            if self.position_type == PositionType.LONG:
                self.take_profit.target_price = self.average_price * Decimal(str(1 + target_percentage / 100))
            else:
                self.take_profit.target_price = self.average_price * Decimal(str(1 - target_percentage / 100))
    
    def add_alert(self, alert: PositionAlert) -> None:
        """添加告警"""
        self.alerts.append(alert)
    
    def get_return_rate(self) -> float:
        """获取收益率"""
        if self.cost_basis == 0:
            return 0.0
        return float(self.total_pnl / self.cost_basis)
    
    def get_summary(self) -> Dict[str, Any]:
        """获取持仓摘要"""
        return {
            'position_id': self.position_id,
            'symbol': self.symbol,
            'position_type': self.position_type.value,
            'status': self.status.value,
            'quantity': float(self.quantity),
            'average_price': float(self.average_price),
            'current_price': float(self.current_price),
            'market_value': float(self.market_value),
            'cost_basis': float(self.cost_basis),
            'unrealized_pnl': float(self.unrealized_pnl),
            'realized_pnl': float(self.realized_pnl),
            'total_pnl': float(self.total_pnl),
            'return_rate': self.get_return_rate(),
            'max_profit': float(self.max_profit),
            'max_loss': float(self.max_loss),
            'created_time': self.created_time.isoformat()
        }
    
    def _check_alerts(self) -> None:
        """检查告警条件"""
        for alert in self.alerts:
            if not alert.enabled or alert.triggered:
                continue
            
            triggered = False
            current_value = None
            
            if alert.alert_type == "price":
                current_value = self.current_price
            elif alert.alert_type == "pnl":
                current_value = self.total_pnl
            elif alert.alert_type == "unrealized_pnl":
                current_value = self.unrealized_pnl
            
            if current_value is not None:
                if alert.condition == ">" and current_value > alert.threshold:
                    triggered = True
                elif alert.condition == "<" and current_value < alert.threshold:
                    triggered = True
                elif alert.condition == ">=" and current_value >= alert.threshold:
                    triggered = True
                elif alert.condition == "<=" and current_value <= alert.threshold:
                    triggered = True
                elif alert.condition == "==" and current_value == alert.threshold:
                    triggered = True
            
            if triggered:
                alert.triggered = True
                alert.trigger_time = datetime.now()
                
                # 触发告警回调
                for callback in self.on_alert_callbacks:
                    try:
                        callback(self, alert)
                    except Exception as e:
                        print(f"告警回调执行失败: {e}")
    
    def _check_stop_loss(self) -> None:
        """检查止损条件"""
        if not self.stop_loss.enabled or self.quantity == 0:
            return
        
        stop_triggered = False
        
        if self.stop_loss.stop_price:
            if self.position_type == PositionType.LONG:
                if self.current_price <= self.stop_loss.stop_price:
                    stop_triggered = True
            else:
                if self.current_price >= self.stop_loss.stop_price:
                    stop_triggered = True
        
        # 移动止损逻辑
        if self.stop_loss.trailing_stop and self.stop_loss.trailing_percentage:
            if self.position_type == PositionType.LONG:
                new_stop = self.max_price * Decimal(str(1 - self.stop_loss.trailing_percentage / 100))
                if not self.stop_loss.stop_price or new_stop > self.stop_loss.stop_price:
                    self.stop_loss.stop_price = new_stop
            else:
                new_stop = self.min_price * Decimal(str(1 + self.stop_loss.trailing_percentage / 100))
                if not self.stop_loss.stop_price or new_stop < self.stop_loss.stop_price:
                    self.stop_loss.stop_price = new_stop
        
        if stop_triggered:
            # 创建止损告警
            alert = PositionAlert(
                alert_id=f"stop_loss_{self.position_id}_{datetime.now().timestamp()}",
                position_id=self.position_id,
                alert_type="stop_loss",
                condition="triggered",
                threshold=self.stop_loss.stop_price or Decimal('0'),
                message=f"持仓 {self.symbol} 触发止损，当前价格: {self.current_price}"
            )
            
            for callback in self.on_alert_callbacks:
                try:
                    callback(self, alert)
                except Exception as e:
                    print(f"止损告警回调执行失败: {e}")
    
    def _check_take_profit(self) -> None:
        """检查止盈条件"""
        if not self.take_profit.enabled or self.quantity == 0:
            return
        
        profit_triggered = False
        
        if self.take_profit.target_price:
            if self.position_type == PositionType.LONG:
                if self.current_price >= self.take_profit.target_price:
                    profit_triggered = True
            else:
                if self.current_price <= self.take_profit.target_price:
                    profit_triggered = True
        
        if profit_triggered:
            # 创建止盈告警
            alert = PositionAlert(
                alert_id=f"take_profit_{self.position_id}_{datetime.now().timestamp()}",
                position_id=self.position_id,
                alert_type="take_profit",
                condition="triggered",
                threshold=self.take_profit.target_price or Decimal('0'),
                message=f"持仓 {self.symbol} 触发止盈，当前价格: {self.current_price}"
            )
            
            for callback in self.on_alert_callbacks:
                try:
                    callback(self, alert)
                except Exception as e:
                    print(f"止盈告警回调执行失败: {e}")


class PositionManager:
    """
    持仓管理器
    
    管理所有持仓，提供风险控制和监控功能。
    """
    
    def __init__(self):
        """初始化持仓管理器"""
        self.positions: Dict[str, Position] = {}
        self.symbol_positions: Dict[str, List[str]] = {}  # 按证券分组的持仓ID
        
        # 风险控制参数
        self.max_position_size = Decimal('1000000')  # 单个持仓最大规模
        self.max_concentration = 0.3  # 最大集中度
        self.max_leverage = 3.0  # 最大杠杆
        
        # 回调函数
        self.on_position_created_callbacks: List[Callable] = []
        self.on_position_updated_callbacks: List[Callable] = []
        self.on_risk_alert_callbacks: List[Callable] = []
    
    def create_position(
        self,
        position_id: str,
        symbol: str,
        position_type: PositionType = PositionType.LONG,
        initial_quantity: Decimal = Decimal('0'),
        initial_price: Decimal = Decimal('0')
    ) -> Position:
        """创建持仓"""
        if position_id in self.positions:
            raise ValueError(f"持仓 {position_id} 已存在")
        
        position = Position(
            position_id=position_id,
            symbol=symbol,
            position_type=position_type,
            initial_quantity=initial_quantity,
            initial_price=initial_price
        )
        
        self.positions[position_id] = position
        
        # 按证券分组
        if symbol not in self.symbol_positions:
            self.symbol_positions[symbol] = []
        self.symbol_positions[symbol].append(position_id)
        
        # 添加回调
        position.on_update_callbacks.append(self._on_position_update)
        position.on_alert_callbacks.append(self._on_position_alert)
        
        # 触发创建回调
        for callback in self.on_position_created_callbacks:
            try:
                callback(position)
            except Exception as e:
                print(f"持仓创建回调执行失败: {e}")
        
        return position
    
    def get_position(self, position_id: str) -> Optional[Position]:
        """获取持仓"""
        return self.positions.get(position_id)
    
    def get_positions_by_symbol(self, symbol: str) -> List[Position]:
        """获取指定证券的所有持仓"""
        position_ids = self.symbol_positions.get(symbol, [])
        return [self.positions[pid] for pid in position_ids if pid in self.positions]
    
    def list_positions(self, status: Optional[PositionStatus] = None) -> List[Position]:
        """列出持仓"""
        positions = list(self.positions.values())
        if status:
            positions = [p for p in positions if p.status == status]
        return positions
    
    def update_prices(self, price_data: Dict[str, Decimal]) -> None:
        """批量更新价格"""
        for symbol, price in price_data.items():
            positions = self.get_positions_by_symbol(symbol)
            for position in positions:
                position.update_price(price)
    
    def get_total_value(self) -> Decimal:
        """获取总持仓价值"""
        total = sum(position.market_value for position in self.positions.values())
        return total if total else Decimal('0')
    
    def get_total_pnl(self) -> Decimal:
        """获取总盈亏"""
        total = sum(position.total_pnl for position in self.positions.values())
        return total if total else Decimal('0')
    
    def get_concentration_risk(self) -> Dict[str, float]:
        """获取集中度风险"""
        total_value = self.get_total_value()
        if total_value == 0:
            return {}
        
        symbol_values = {}
        for position in self.positions.values():
            if position.symbol not in symbol_values:
                symbol_values[position.symbol] = Decimal('0')
            symbol_values[position.symbol] += position.market_value
        
        return {
            symbol: float(value / total_value)
            for symbol, value in symbol_values.items()
        }
    
    def check_risk_limits(self) -> List[Dict[str, Any]]:
        """检查风险限制"""
        violations = []
        
        # 检查单个持仓规模
        for position in self.positions.values():
            if position.market_value > self.max_position_size:
                violations.append({
                    'type': 'position_size',
                    'position_id': position.position_id,
                    'symbol': position.symbol,
                    'current_value': float(position.market_value),
                    'limit': float(self.max_position_size),
                    'message': f"持仓 {position.symbol} 规模超限"
                })
        
        # 检查集中度风险
        concentrations = self.get_concentration_risk()
        for symbol, concentration in concentrations.items():
            if concentration > self.max_concentration:
                violations.append({
                    'type': 'concentration',
                    'symbol': symbol,
                    'current_concentration': concentration,
                    'limit': self.max_concentration,
                    'message': f"证券 {symbol} 集中度过高"
                })
        
        return violations
    
    def get_summary(self) -> Dict[str, Any]:
        """获取管理器摘要"""
        active_positions = [p for p in self.positions.values() if p.status == PositionStatus.OPEN]
        
        return {
            'total_positions': len(self.positions),
            'active_positions': len(active_positions),
            'total_value': float(self.get_total_value()),
            'total_pnl': float(self.get_total_pnl()),
            'concentration_risk': self.get_concentration_risk(),
            'risk_violations': self.check_risk_limits()
        }
    
    def _on_position_update(self, position: Position) -> None:
        """持仓更新回调"""
        for callback in self.on_position_updated_callbacks:
            try:
                callback(position)
            except Exception as e:
                print(f"持仓更新回调执行失败: {e}")
    
    def _on_position_alert(self, position: Position, alert: PositionAlert) -> None:
        """持仓告警回调"""
        for callback in self.on_risk_alert_callbacks:
            try:
                callback(position, alert)
            except Exception as e:
                print(f"风险告警回调执行失败: {e}")